using System;
using System.Collections.Generic;
using System.Linq;
using T.FAS.Runtime.Base.Entity;
using T.FAS.Runtime.Metadata.Entity.DataModel;
using T.FAS.Runtime.Metadata.Client;
using T.FAS.Runtime.Metadata.SPI;
using T.FAS.Runtime.DataAccess.Common;

namespace T.FAS.Runtime.DataAccess.Engine
{
    /// <summary>
    /// TRecord扩展方法
    /// </summary>
    public static class TRecordEngineExtension
    {
        /// <summary>
        /// 获取TRecord指定属性值，特殊处理特殊类型
        /// </summary>
        /// <returns></returns>
        public static UpdateChangeSet GetUpdataChangeSetForEngine(this TRecord record, CompositeNodeObject cno)
        {
            UpdateChangeSet set = new UpdateChangeSet
            {
                ChangeSetItems = new List<TChangeSetItem>()
            };
            if (record.ChangeType == TRecordChangeType.Update 
                || (record.ChangeSet != null && record.ChangeSet.ChangeType == TRecordChangeType.Update)
                || record.ChangeType == TRecordChangeType.Add
                || (record.ChangeSet != null && record.ChangeSet.ChangeType == TRecordChangeType.Add))
            {
                if (record.ChangeSet?.ChangeSetItems != null)
                {
                    foreach (var item in record.ChangeSet.ChangeSetItems)
                    {
                        set.ChangeSetItems.Add(item.Clone());
                    }
                    var pkField = cno.GetPKColumn();
                    var pkVal = record.GetValue(pkField.ColumnName);
                    //将各个节点的主键ID记录到变更中，为了通过Update条件数量校验
                    set.ChangeSetItems.Add(new TChangeSetItem
                    {
                        BusinessType = BusinessType.Normal,
                        ColumnCode = pkField.ColumnName,
                        ColumnName = pkField.DisplayName,
                        InitValue = pkVal,
                        InitDisplayName = pkField.DisplayName,
                        OldValue = null,
                        OldDisplayValue = pkField.DisplayName,
                        NewValue = pkVal,
                        NewDisplayValue = pkField.DisplayName,
                    });

                    var timeField = cno.GetTimestampElement()?.DataColumn;
                    //如果时间戳字段不存在，跳过
                    if (timeField != null)
                    {
                        var timeVal = record.GetValue(timeField.ColumnName);
                        //将时间戳字段单独记录变更项，为了通过时间戳校验
                        set.ChangeSetItems.Add(new TChangeSetItem
                        {
                            BusinessType = BusinessType.Normal,
                            ColumnCode = timeField.ColumnName,
                            ColumnName = timeField.DisplayName,
                            InitValue = timeVal,
                            InitDisplayName = timeField.DisplayName,
                            OldValue = null,
                            OldDisplayValue = timeField.DisplayName,
                            NewValue = timeVal,
                            NewDisplayValue = timeField.DisplayName,
                            DataType = DataType.Timestamp,
                        });
                    }
                }
            }
            return set;
        }

        public static List<TRecordDebugInfo> GetTRecordDebugInfos(this TRecord record, int depth = 0)
        {
            try
            {
                if (depth > 5) return default;
                List<TRecordDebugInfo> debugInfos = new List<TRecordDebugInfo>();
                debugInfos.Add(new TRecordDebugInfo
                {
                    RecordIdentifier = record.TRecordID,
                    Record = record,
                    ChangeSet = record.ChangeSet,
                    ChangeSetItems = record.ChangeSet.ChangeSetItems,
                    OtherInfo = new { RecordChangeSet = record.ChangeType, ChangeSetChangeType = record.ChangeSet.ChangeType },
                });

                foreach (var attr in record.GetProperties())
                {
                    if (record[attr] is TRecord childRecord && childRecord != null)
                    {
                        var result = GetTRecordDebugInfos(childRecord, depth + 1);
                        if (result != null && result.Count > 0)
                            debugInfos.AddRange(result);
                    }
                    else
                    {
                        if (record[attr] is List<TRecord> list && list != null && list.Count > 0)
                        {
                            foreach (var child in list)
                            {
                                var result = GetTRecordDebugInfos(child, depth + 1);
                                if (result != null && result.Count > 0)
                                    debugInfos.AddRange(result);
                            }
                        }
                    }
                }
                return debugInfos;

            }
            catch (Exception e)
            {
                return null;
            }
        }
    }

    /// <summary>
    /// DQ扩展方法
    /// </summary>
    public static class DQEngineExtension
    {
        /// <summary>
        /// 重新构建DQ引用关系，不包含SubQuery子查询初始化，供运行时使用
        /// </summary>
        public static void RebuildRelationForEngine(this DataQuery dataquery)
        {
            var unifyCode = DataModelErrorCode.GetUnifiedErrorCode(DataModelConst.DQMetaType, dataquery.ID, dataquery.Code);
            try
            {
                //为datasource填充DO实例
                foreach (var source in dataquery.DataQuerySources)
                {
                    if (source.DataObject == null)  //兼容json反序列化处理，如果source.DataObject不为空，则为反序列化出来的DO，直接处理即可。目前Entity不依赖RTP.GetMetadata，所以抛出异常
                    {
                        IMetaDataClientService metaDataClientService = MetaDataClientService.GetInstance();
                        source.DataObject = metaDataClientService.GetMetaData(source.DataObjectID).Content as DataObject;
                        if (source.DataObject == null)
                            throw new FasException(DataModelErrorCode.DQ.InitError, string.Format(CommonStringClassEngine.DQEngineExtension_RebuildRelationForEngine,unifyCode,source.Alias,source.DataObjectID));
                    }
                }
                var DQ_DOs = dataquery.DataQuerySources.Select(s => s.DataObject).ToList();
                //为datacolumn填充实例
                var needRebuildColumns = dataquery.DataQueryColumns.Where(col => col.DataObject == null || col.DataColumn == null);
                var needRebuildSorts = dataquery.DataQuerySorts?.Where(sort => sort.SortItemType == 0 && (sort.DataObject == null || sort.DataColumn == null));
                var needRebuildJoins = dataquery.DataQueryJoins?.Where(join => join.LeftQuerySource == null || join.RightQuerySource == null);
                foreach (var column in needRebuildColumns)
                {
                    if (column.ColumnType == ColumnType.Normal)
                    {
                        column.DataObject = DQ_DOs.Find(o => o.ID == column.DataObjectID);
                        column.DataColumn = column.DataObject.Columns.Find(col => col.ID == column.DataObjectColumnID);
                    }
                    else
                    {
                        //聚合列也需要填充DO及列信息
                        if (!string.IsNullOrEmpty(column.DataObjectID))
                        {
                            column.DataObject = DQ_DOs.Find(o => o.ID == column.DataObjectID);
                            column.DataColumn = column.DataObject.Columns.Find(col => col.ID == column.DataObjectColumnID);
                        }
                    }
                    if (!string.IsNullOrEmpty(column.DataObjectID))
                    {
                        if (column.DataObject == null)
                        {
                            throw new FasException(DataModelErrorCode.DQ.InitError, string.Format(CommonStringClassEngine.DQEngineExtension_RebuildRelationForEngine1,unifyCode,column.Name));
                        }
                    }
                }
                //为datasort填充实例
                if (needRebuildSorts != null && needRebuildSorts.Count() > 0)
                {
                    foreach (var sort in needRebuildSorts)
                    {
                        sort.DataObject = DQ_DOs.Find(o => o.ID == sort.DataObjectID);
                        sort.DataColumn = sort.DataObject.Columns.Find(col => col.ID == sort.DataObjectColumnID);
                    }
                }
                //填充Join实例
                if (needRebuildJoins != null && needRebuildJoins.Count() > 0)
                {
                    foreach (var join in needRebuildJoins)
                    {
                        join.LeftQuerySource = dataquery.DataQuerySources.Find(s => s.ID == join.LeftSourceID);
                        join.RightQuerySource = dataquery.DataQuerySources.Find(s => s.ID == join.RightSourceID);
                    }
                }
                //不负责构建子DQ引用，应递归调用本方法
                if (dataquery.SubQuerys != null)
                {
                }
            }
            catch (Exception e)
            {
                throw new FasException(DataModelErrorCode.DQ.InitError, string.Format(CommonStringClassEngine.DQEngineExtension_RebuildRelationForEngine2,unifyCode), e);
            }
        }
    }
}
